Skip to content

feat(telemetry): USDT probes for tracing spans end - #257

Open
jsitnicki wants to merge 2 commits into
cloudflare:mainfrom
jsitnicki:jakub/PERF-2835-span-with-probe
Open

feat(telemetry): USDT probes for tracing spans end#257
jsitnicki wants to merge 2 commits into
cloudflare:mainfrom
jsitnicki:jakub/PERF-2835-span-with-probe

Conversation

@jsitnicki

Copy link
Copy Markdown

Problem

Code bases which use foundations are already instrumented with tracing spans, but there is no easy way to measure the duration of a specific span with a BPF-based tracer, like bpftrace or ebpf_exporter. One would have to craft custom uprobes at code offsets that shift with every build, and match span start/end events across await points and thread hops.

Solution

span_with_probe!("span::name") — a drop-in replacement for tracing::span("...") that additionally emits a per-span USDT probe at span end, span_end_<sanitized name>, receiving the span duration (ns) as an argument.

Key features:

  • Attaching is zero-cost for everything else: each call site gets a probe semaphore that tracers bump on attach; unattached spans don't even record a timestamp.
  • Works regardless of span sampling — probes fire with tracing disabled.
  • linux/x86_64 only; other platforms degrade to plain tracing::span. aarch64 support to follow.
  • Comes with a demo workload + bpftrace script, examples/span_with_probe, to show the intended use.

/// semaphore in `.probes`). The two `{}` operands are the semaphore symbol
/// and the duration argument.
///
/// `usdt_provider` must not contain `:` (bpftrace attach points are

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a check for this when expanding the macro

…ption

Our code bases are already instrumented with tracing spans, but there is
no easy way to attach a BPF tracer to a specific span's start/end and
measure its duration: one would have to craft custom uprobes at specific
code offsets, which shift with every build, and then match span start and
end events to each other across await points and thread hops, since an
async span can be suspended and resumed on a different thread.

span_with_probe! (and its span_fn attribute counterpart, end_probe =
true) emit a per-span USDT probe named span_end__<sanitized span name>
which fires at span end with the span duration as an argument, so a
tracer can attach to a single span by name while all other spans pay no
cost. The probe is armed via a per-span semaphore only while a tracer is
attached and works regardless of span sampling.

The USDT provider defaults to the FOUNDATIONS_USDT_PROVIDER environment
variable at compile time (settable per project via [env] in
.cargo/config.toml), or "foundations" when unset, and can be overridden
per call site with usdt_provider = "...".
Runs spans instrumented with span_with_probe! and span_fn's end_probe
option in a loop, with distinct delay ranges so their durations can be
told apart. Comes with a bpftrace script that attaches to the span end
probes and prints duration histograms.
@jsitnicki
jsitnicki force-pushed the jakub/PERF-2835-span-with-probe branch from f84e8b1 to 7ec8942 Compare August 28, 2026 10:17
@jsitnicki

Copy link
Copy Markdown
Author

Per our discussion off-line, reworked the changes to support span_fn.

This called for a completely different approach than in span_with_probe! case.
Wrapping an existing span_fn macro with another macro (span_fn_with_probe?)
seemed silly. I've added a new option instead - end_probe. span_fn shares
what's possible with span_with_probe!.

Other changes:

Open question: Do we want to mark this as unstable and gate it be a crate
feature for now? How flexible are we on public API changes?

What's next? As a follow-up I will work on probe-rs to:

  1. Propose the public API change that would let us drop the asm! snippets in
    foundations.
  2. Add aarch64 support.
  3. Add optimized syscall-based USDT (nop,nop10 combo) probe support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants